package com.liy.teaching.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liy.teaching.common.RedisLock;
import com.liy.teaching.entity.ProductEntity;
import com.liy.teaching.mapper.ProductMapper;
import com.liy.teaching.service.ProductService;
import com.liy.teaching.util.JSONUtil;
import org.redisson.RedissonLock;
import org.redisson.api.RBloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;

/**
 * 布隆过滤器判断 不存在  准确率100%
 * 可以判断某样东西一定不存在
 * <p>
 * 商品服务
 **/
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductEntity> implements ProductService {

    //前缀
    private static final String KEY_PREFIX = "product:";

    //  格式化一下
    private static String buildKey(String id) {
        return KEY_PREFIX + id;  // product:商品ID
    }


    @Resource(name = "redisTemplate")
    private ValueOperations<Serializable, String> redisOperations;


    @Autowired
    private RBloomFilter<String> redisBloomFilter;


    @Autowired
    private RedisLock redisLock;   // 自己封装的 redisLock


    /**
     * 重载 getById(id)  做第一点增强
     */
    @Override
    public ProductEntity getById(Serializable id) {

        String redisKey = buildKey(String.valueOf(id)); // 构建rediskey

        if (!redisBloomFilter.contains(redisKey)) {  // 布隆过滤器判断 redisKey 不存在
            return null;
        }

        String redisValue = redisOperations.get(redisKey);  // 从缓存中去查

        if (redisValue != null) {  // 查到了
            return JSONUtil.parseObject(redisValue, ProductEntity.class); //直接返回;
        }

        // 在查询 DB 之前加锁
        redisLock.lock(String.valueOf(id));

        try{

            // 再一次查询缓存, 是为了分布式并发情况下, 其他并发的请求, 能在锁解开之后, 再次查缓存
            String redisValue2 = redisOperations.get(redisKey);

            if (redisValue2 != null) {
                return JSONUtil.parseObject(redisValue, ProductEntity.class);
            }

            ProductEntity product = getBaseMapper().selectById(id); // 从数据库中查

            if (product != null) {
                String jsonString = JSONUtil.toJSONString(product);
                redisOperations.set(redisKey, jsonString);    // 放到缓存中
                return product;
            }
            return null;

        }finally {
            redisLock.unlock(String.valueOf(id));   // 无论如何都要释放锁
        }

    }

}
